#include "asm/includes.h"
#include "typedef.h"
#include "printf.h"
#include "chargestore.h"
#include "asm/spi.h"
#include "asm/adc_api.h"
#include "asm/iic_hw.h"
#include "asm/iic_soft.h"
#include "vm_id.h"
#include "asm/gpio.h"

#define CONFIG_DEBUG_ENABLE     1
#define TCFG_CHARGE_ENABLE      1
#define TCFG_TEST_BOX_ENABLE    0
#define TCFG_LOWPOWER_LOWPOWER_SEL BIT(2)
#define TCFG_LOWPOWER_POWER_SEL				PWR_LDO15//电源模式设置，可选DCDC和LDO

#define TCFG_CLOCK_MODE     CLOCK_MODE_ADAPTIVE

#define ENABLE								1
#define DISABLE								0
#define TCFG_HW_SPI1_ENABLE     1
#define TCFG_HW_SPI2_ENABLE     1
#define TCFG_HW_IIC_ENABLE      1
#define TCFG_SOFT_IIC_ENABLE    1

#define TCFG_CLOCK_OSC_HZ       24000000
#define TCFG_CLOCK_SYS_HZ       24000000

/************************** debug uart config ****************************/
const struct uart_platform_data debug_uart_config = {
    .tx_pin = IO_PORTA_09,
    .tx_ch_sel = CH2_UT2_TX,//CH0_UT2_TX/CH1_UT2_TX/CH2_UT2_TX, 发送IO通道选择,选择enum OUTPUT_CH_SEL，不使用时赋值0xff
    .rx_pin = 0xff,
    .baudrate = 1000000,
};

/************************** SPI config ****************************/
#if TCFG_HW_SPI1_ENABLE
const struct spi_platform_data spi1_p_data = {
    //SPI1 A:PB00,PB01,PB02 (clk,do,di)
    //SPI1 B:PC04,PC05,PC03 (clk,do,di)
    .port = 'A',
    .mode = SPI_MODE_BIDIR_1BIT,
    .clk = 1000000,
    .role = SPI_ROLE_MASTER,
};
#endif
#if TCFG_HW_SPI2_ENABLE
const struct spi_platform_data spi2_p_data = {
    //SPI2 A:PB09, PB10, PB08 (clk,do,di)
    //SPI2 B:USBDP,USBDM,PA13 (clk,do,di)
    .port = 'A',
    .mode = SPI_MODE_BIDIR_1BIT,
    .clk = 1000000,
    .role = SPI_ROLE_SLAVE,
};
#endif
/************************** IIC config ****************************/
#if TCFG_HW_IIC_ENABLE
const struct hw_iic_config hw_iic_cfg[] = {
    //iic0 data
    {
        //   SCL          SDA
        //IO_PORT_DP, IO_PORT_DM    //group A
        //IO_PORTC_04, IO_PORTC_05  //group B
        //IO_PORTB_04, IO_PORTB_06  //group C
        //IO_PORTA_05, IO_PORTA_06  //group D
        .port = 'B',
        .baudrate = 100000,      //IIC通讯波特率
        .hdrive = 0,             //是否打开IO口强驱
        .io_filter = 1,          //是否打开滤波器（去纹波）
        .io_pu = 1,              //是否打开上拉电阻，如果外部电路没有焊接上拉电阻需要置1
        .role = IIC_MASTER,
    },
};
#endif
#if TCFG_SOFT_IIC_ENABLE
const struct soft_iic_config soft_iic_cfg[] = {
    {
        //iic0 data
        .scl = IO_PORTC_02,      //IIC CLK脚
        .sda = IO_PORTC_03,      //IIC DAT脚
        .delay = 50,             //软件IIC延时参数，影响通讯时钟频率
        .io_pu = 1,              //是否打开上拉电阻，如果外部电路没有焊接上拉电阻需要置1
    },
#if 0
    {
        //iic1 data
        .scl = IO_PORTA_06,
        .sda = IO_PORTA_07,
        .delay = 50,
        .io_pu = 1,
    },
#endif
};
#endif

/************************** CHARGE config****************************/
#if TCFG_CHARGE_ENABLE
struct charge_platform_data charge_data = {
    .charge_full_V          = CHARGE_FULL_V_4202,               //充电截止电压
    .charge_full_mA			= CHARGE_FULL_mA_10,                //充电截止电流
    .charge_mA				= CHARGE_mA_60,                     //充电电流
    /*充满判定过滤值，过滤时间 = (filter*2)ms,(WPWR>VBAT)&充满信号且时间大于过滤时间才认为充满*/
    .charge_full_filter     = 5,
    /*vpwr拔出过滤值，过滤时间 = (filter*2)ms,VPWR<0.6V且时间大于过滤时间才认为拔出*/
    .vpwr_off_filter		= 100,
    /*vpwr插入过滤值，过滤时间 = (filter*2)ms,WPWR>VBAT且时间大于过滤时间才认为插入*/
    .vpwr_on_filter         = 50,
    /*vpwr维持电压过滤值，过滤时间 = (filter*2)ms,0.6<WPWR<VBAT且时间大于过滤时间才认为是维持电压*/
    .vpwr_keep_filter       = 220,
};
#endif//TCFG_CHARGE_ENABLE

/************************** chargestore config****************************/
#if TCFG_TEST_BOX_ENABLE
static const struct chargestore_platform_data chargestore_data = {
    .baudrate               = 9600,
    .io_port                = IO_PORTB_05,
    .init                   = chargestore_init,
    .open                   = chargestore_open,
    .close                  = chargestore_close,
    .write                  = chargestore_write,
    .set_callback           = chargestore_set_data_callback,
    .set_update             = chargestore_set_update_ram,
};
#endif


/************************** key driver config****************************/
#if (USE_KEY_DRIVER == 1)
//2个测试io按键
u16 io_key_table[2] = {
    IO_PORTA_01,
    IO_PORTA_02,
};
#endif


void debug_uart_early_init()
{
#if CONFIG_DEBUG_ENABLE
    debug_uart_init(&debug_uart_config);
#endif
}

/************************** power_param ****************************/
const struct low_power_param power_param = {
    .config         = TCFG_LOWPOWER_LOWPOWER_SEL,          //使能powerdown
    .btosc_hz       = TCFG_CLOCK_OSC_HZ,                   //外接晶振频率
    .delay_us       = TCFG_CLOCK_SYS_HZ / 1000000L,        //提供给低功耗模块的延时(不需要需修改)
    .btosc_disable  = 0,                                   //进入低功耗时BTOSC是否保持
    .vddiom_lev     = VDDIOM_VOL_30V,                      //强VDDIO等级,可选：2.0V  2.2V  2.4V  2.6V  2.8V  3.0V  3.2V  3.6V
    .vddiow_lev     = VDDIOW_VOL_28V,                      //弱VDDIO等级,可选：2.1V  2.4V  2.8V  3.2V
    .osc_type       = OSC_TYPE_LRC,                        //低功耗使用时钟源
};

/************************** wk_param ****************************/
struct port_wakeup port0 = {
    .pullup_down_enable = ENABLE,                          //配置I/O 内部上下拉是否使能
    .edge       = FALLING_EDGE,                            //唤醒方式选择,可选：上升沿\下降沿
    .attribute  = BLUETOOTH_RESUME,                        //保留参数
    .iomap      = IO_PORTB_01,                             //唤醒口选择
};

const struct sub_wakeup sub_wkup = {
    .attribute  = BLUETOOTH_RESUME,
};

const struct charge_wakeup charge_wkup = {
    .attribute  = BLUETOOTH_RESUME,
};

const struct wakeup_param wk_param = {
    .port[1] = &port0,
    .sub = &sub_wkup,
    .charge = &charge_wkup,
};

extern void dac_power_off(void);
extern void dac_sniff_power_off(void);
int gpio_dir(u32 gpio, u32 start, u32 len, u32 dat, enum gpio_op_mode op);
int gpio_set_pu(u32 gpio, u32 start, u32 len, u32 dat, enum gpio_op_mode op);
int gpio_set_pd(u32 gpio, u32 start, u32 len, u32 dat, enum gpio_op_mode op);
int gpio_die(u32 gpio, u32 start, u32 len, u32 dat, enum gpio_op_mode op);
int gpio_dieh(u32 gpio, u32 start, u32 len, u32 dat, enum gpio_op_mode op);
void board_set_soft_poweroff(void)
{
    u8 mode = (JL_SFC->CON >> 8) & 0x0f;

    u32 porta_value = 0xffff;
    u32 portb_value = 0xffff;
    u32 portc_value = 0xffff;

    extern u32 spi_get_port(void);
    if (spi_get_port() != 0) {
        if ((mode == 0b0101) || (mode == 0b0111)) {
            porta_value = 0x1fff;
        } else {
            porta_value = 0x9fff;
        }
    }

    gpio_dir(GPIOA, 0, 16, porta_value, GPIO_OR);
    gpio_set_pu(GPIOA, 0, 16, ~porta_value, GPIO_AND);
    gpio_set_pd(GPIOA, 0, 16, ~porta_value, GPIO_AND);
    gpio_die(GPIOA, 0, 16, ~porta_value, GPIO_AND);
    gpio_dieh(GPIOA, 0, 16, ~porta_value, GPIO_AND);

    //保留长按Reset Pin - PB1
    portb_value &= ~BIT(1);
    gpio_dir(GPIOB, 0, 16, portb_value, GPIO_OR);
    gpio_set_pu(GPIOB, 0, 16, ~portb_value, GPIO_AND);
    gpio_set_pd(GPIOB, 0, 16, ~portb_value, GPIO_AND);
    gpio_die(GPIOB, 0, 16, ~portb_value, GPIO_AND);
    gpio_dieh(GPIOB, 0, 16, ~portb_value, GPIO_AND);

    gpio_dir(GPIOC, 0, 16, portc_value, GPIO_OR);
    gpio_set_pu(GPIOC, 0, 16, ~portc_value, GPIO_AND);
    gpio_set_pd(GPIOC, 0, 16, ~portc_value, GPIO_AND);
    gpio_die(GPIOC, 0, 16, ~portc_value, GPIO_AND);
    gpio_dieh(GPIOC, 0, 16, ~portc_value, GPIO_AND);

    gpio_set_pull_up(IO_PORT_DP, 0);
    gpio_set_pull_down(IO_PORT_DP, 0);
    gpio_set_direction(IO_PORT_DP, 1);
    gpio_set_die(IO_PORT_DP, 0);
    gpio_set_dieh(IO_PORT_DP, 0);

    gpio_set_pull_up(IO_PORT_DM, 0);
    gpio_set_pull_down(IO_PORT_DM, 0);
    gpio_set_direction(IO_PORT_DM, 1);
    gpio_set_die(IO_PORT_DM, 0);
    gpio_set_dieh(IO_PORT_DM, 0);

#if (TCFG_SD0_ENABLE || TCFG_SD1_ENABLE)
    sdpg_config(0);
#endif
}

void sleep_exit_callback(u32 usec)
{
    putchar('>');
}

void sleep_enter_callback(u8  step)
{
    /* 此函数禁止添加打印 */
    if (step == 1) {
        putchar('<');
        /* dac_power_off(); */
    } else {
        gpio_set_pull_up(IO_PORTA_03, 0);
        gpio_set_pull_down(IO_PORTA_03, 0);
        gpio_set_direction(IO_PORTA_03, 1);

        usb_iomode(1);

        gpio_set_pull_up(IO_PORT_DP, 0);
        gpio_set_pull_down(IO_PORT_DP, 0);
        gpio_set_direction(IO_PORT_DP, 1);
        gpio_set_die(IO_PORT_DP, 0);

        gpio_set_pull_up(IO_PORT_DM, 0);
        gpio_set_pull_down(IO_PORT_DM, 0);
        gpio_set_direction(IO_PORT_DM, 1);
        gpio_set_die(IO_PORT_DM, 0);
    }
}

static void wl_audio_clk_on(void)
{
}

void board_power_init(void)
{
    power_init(&power_param);

    power_set_callback(TCFG_LOWPOWER_LOWPOWER_SEL, sleep_enter_callback, sleep_exit_callback, board_set_soft_poweroff);

    wl_audio_clk_on();

    power_wakeup_init(&wk_param);
}

void board_init()
{
    adc_init();

    board_power_init();

    /* power_trim(VM_PMU_VOLTAGE, 0); */

#if TCFG_CHARGE_ENABLE
    charge_init(&charge_data);
    /* clk_update_voltage_by_freq(TCFG_CHARGE_ENABLE); */
#else
    CHGBG_EN(0);
    CHARGE_EN(0);
#endif

#if TCFG_TEST_BOX_ENABLE
    chargestore_api_init(&chargestore_data);
#endif


    /* power_set_mode(TCFG_LOWPOWER_POWER_SEL); */
}
